// 音高检测工具类
export class PitchDetector {
  constructor() {
    this.audioContext = null;
    this.audioBuffer = null;
    this.sampleRate = 44100;
  }

  // 初始化音频上下文
  async initAudioContext() {
    if (!this.audioContext) {
      this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
    }
  }

  // 加载音频文件
  async loadAudioFile(file) {
    await this.initAudioContext();
    
    const arrayBuffer = await file.arrayBuffer();
    this.audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
    this.sampleRate = this.audioBuffer.sampleRate;
    
    return {
      duration: this.audioBuffer.duration,
      sampleRate: this.sampleRate,
      numberOfChannels: this.audioBuffer.numberOfChannels
    };
  }

  // 从音频缓冲区获取指定时间段的数据
  getAudioSegment(startTime, endTime) {
    if (!this.audioBuffer) {
      throw new Error('音频文件未加载');
    }

    const startSample = Math.floor(startTime * this.sampleRate);
    const endSample = Math.floor(endTime * this.sampleRate);
    const segmentLength = endSample - startSample;

    // 获取第一个声道的数据
    const channelData = this.audioBuffer.getChannelData(0);
    const segment = channelData.slice(startSample, endSample);

    return segment;
  }

  // 使用FFT进行频率分析
  analyzeFrequency(audioData, windowSize = 2048) {
    // 应用汉宁窗
    const windowedData = this.applyHanningWindow(audioData, windowSize);
    
    // 进行FFT
    const fftResult = this.fft(windowedData);
    
    // 计算幅度谱
    const magnitudes = fftResult.map(complex => 
      Math.sqrt(complex.real * complex.real + complex.imag * complex.imag)
    );

    // 找到最大峰值对应的频率
    const maxIndex = this.findMaxPeakIndex(magnitudes.slice(0, windowSize / 2));
    const frequency = (maxIndex * this.sampleRate) / windowSize;

    return frequency;
  }

  // 应用汉宁窗函数
  applyHanningWindow(data, windowSize) {
    const windowed = new Array(windowSize).fill(0);
    const dataLength = Math.min(data.length, windowSize);
    
    for (let i = 0; i < dataLength; i++) {
      const windowValue = 0.5 * (1 - Math.cos(2 * Math.PI * i / (windowSize - 1)));
      windowed[i] = data[i] * windowValue;
    }
    
    return windowed;
  }

  // 简化的FFT实现（用于演示，实际项目中建议使用专业的FFT库）
  fft(data) {
    const N = data.length;
    if (N <= 1) return [{ real: data[0] || 0, imag: 0 }];

    // 确保数据长度是2的幂
    let size = 1;
    while (size < N) size *= 2;
    
    const paddedData = [...data];
    while (paddedData.length < size) paddedData.push(0);

    return this.fftRecursive(paddedData.map(x => ({ real: x, imag: 0 })));
  }

  fftRecursive(data) {
    const N = data.length;
    if (N <= 1) return data;

    const even = [];
    const odd = [];
    for (let i = 0; i < N; i += 2) {
      even.push(data[i]);
      if (i + 1 < N) odd.push(data[i + 1]);
    }

    const evenFft = this.fftRecursive(even);
    const oddFft = this.fftRecursive(odd);

    const result = new Array(N);
    for (let k = 0; k < N / 2; k++) {
      const angle = -2 * Math.PI * k / N;
      const twiddle = {
        real: Math.cos(angle),
        imag: Math.sin(angle)
      };

      const oddK = oddFft[k] || { real: 0, imag: 0 };
      const t = {
        real: twiddle.real * oddK.real - twiddle.imag * oddK.imag,
        imag: twiddle.real * oddK.imag + twiddle.imag * oddK.real
      };

      const evenK = evenFft[k] || { real: 0, imag: 0 };
      result[k] = {
        real: evenK.real + t.real,
        imag: evenK.imag + t.imag
      };
      result[k + N / 2] = {
        real: evenK.real - t.real,
        imag: evenK.imag - t.imag
      };
    }

    return result;
  }

  // 找到最大峰值的索引
  findMaxPeakIndex(magnitudes) {
    let maxIndex = 0;
    let maxValue = magnitudes[0];

    for (let i = 1; i < magnitudes.length; i++) {
      if (magnitudes[i] > maxValue) {
        maxValue = magnitudes[i];
        maxIndex = i;
      }
    }

    return maxIndex;
  }

  // 分析指定时间段的音高
  async analyzePitchInTimeRange(startTime, endTime, intervalMs = 20) {
    const audioSegment = this.getAudioSegment(startTime, endTime);
    const intervalSamples = Math.floor((intervalMs / 1000) * this.sampleRate);
    const results = [];

    let currentTime = startTime;
    let sampleIndex = 0;

    while (currentTime < endTime && sampleIndex < audioSegment.length) {
      const segmentEnd = Math.min(sampleIndex + intervalSamples, audioSegment.length);
      const segment = audioSegment.slice(sampleIndex, segmentEnd);

      if (segment.length > 0) {
        const frequency = this.analyzeFrequency(segment);
        const noteName = this.frequencyToNoteName(frequency);
        
        results.push({
          time: currentTime,
          frequency: frequency,
          noteName: noteName
        });
      }

      currentTime += intervalMs / 1000;
      sampleIndex += intervalSamples;
    }

    return results;
  }

  // 频率转换为音名（包含组别）
  frequencyToNoteName(frequency) {
    if (frequency <= 0 || !isFinite(frequency)) {
      return { note: '无', octave: '', fullName: '无音高' };
    }

    // 音名数组
    const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
    
    // A4 = 440Hz 作为参考
    const A4 = 440;
    const A4_INDEX = 9; // A在音名数组中的索引
    const A4_OCTAVE = 4;

    // 计算相对于A4的半音数
    const semitonesFromA4 = Math.round(12 * Math.log2(frequency / A4));
    
    // 计算音名索引和八度（修正负数处理）
    const noteIndex = ((A4_INDEX + semitonesFromA4) % 12 + 12) % 12;
    const octave = A4_OCTAVE + Math.floor((A4_INDEX + semitonesFromA4) / 12);
    
    const finalNoteIndex = noteIndex;
    const finalOctave = octave;

    const note = noteNames[finalNoteIndex];
    const fullName = `${note}${finalOctave}`;

    return {
      note: note,
      octave: finalOctave.toString(),
      fullName: fullName
    };
  }
}
